﻿using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace AutoRegisterAndActive
{
    /// <summary>
    /// 自动注册激活模块
    /// </summary>
    public class AutoRegisterAndActiveModule
    {
        /// <summary>
        /// 自动注册到注册表中
        /// </summary>
        /// <param name="cadVersion"></param>
        /// <param name="dllPath"></param>
        public static void AutoRegister(string cadVersion, string dllPath)
        {
            string cadPath = FindLocation(cadVersion, out List<string> cadRegAddress);

            for (int i = 0; i < cadRegAddress.Count; i++)
            {
                string appRegAddress = cadRegAddress[i] + "\\Applications";
                RegisteringCAD(appRegAddress, dllPath);
            }

        }

        public static void AutoAvtive(string cadVersion, string dllPath, string activeCode)
        {
            string dllName = Path.GetFileNameWithoutExtension(dllPath);
            DateTime overTime = DateTime.Now;
            DateTime registerTime = DateTime.Now;
            if (CheckActive(activeCode, ref overTime, ref registerTime))
            {
                CreateActiveCodeToReg(cadVersion, dllPath, activeCode);
            };
        }

        /// <summary>
        /// 创建机器码
        /// </summary>
        /// <returns></returns>
        public static string CreateMachineCode() 
        { 
            return DeviceHelper.GetMachineCode();
        }

        /// <summary>
        /// 输入激活码确认是否激活
        /// </summary>
        /// <param name="registerCode"></param>
        /// <param name="overTime"></param>
        /// <param name="registerTime"></param>
        /// <returns></returns>
        public static bool CheckActive(string registerCode, ref DateTime overTime, ref DateTime registerTime)
        {
            string machineCodeEncryptKey = "1996";
            try
            {
                var finalCodeList = ToDecryptString(machineCodeEncryptKey, registerCode).Split('&');
                if (finalCodeList.Length == 3)
                {
                    DateTime.TryParse(finalCodeList[1], out overTime);
                    DateTime.TryParse(finalCodeList[2], out registerTime);
                    //获取本地机器码
                    var machineCode = DeviceHelper.GetMachineCode();
                    return machineCode != null && (finalCodeList[0] == machineCode);
                }
                else
                {
                    return false;
                }
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 字符串解密
        /// </summary>
        /// <param name="key"></param>
        /// <param name="str"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        private static string ToDecryptString(string key, string str)
        {
            try
            {
                //将密钥字符串转换为字节序列
                var P_byte_key = Encoding.Unicode.GetBytes(key);
                //将加密后的字符串转换为字节序列
                var P_byte_data = Convert.FromBase64String(str);
                //创建内存流对象并写入数据,创建加密流对象
                CryptoStream cStream = new CryptoStream(new MemoryStream(P_byte_data), new DESCryptoServiceProvider().CreateDecryptor(P_byte_key, P_byte_key), CryptoStreamMode.Read);
                //创建字节序列对象
                var tempDate = new byte[200];
                //创建内存流对象
                MemoryStream mStream = new MemoryStream();
                //创建记数器
                int i = 0;
                //使用while循环得到解密数据
                while ((i = cStream.Read(tempDate, 0, tempDate.Length)) > 0)
                {
                    //将解密后的数据放入内存流
                    mStream.Write(tempDate, 0, i);
                }
                var res = Encoding.Unicode.GetString(mStream.ToArray());
                mStream.Dispose();
                cStream.Dispose();
                return res;
            }
            catch (CryptographicException ce)
            {
                throw new Exception(ce.Message);
            }
        }

        /// <summary>
        /// 将激活码注册到注册表上
        /// </summary>
        /// <param name="cadVersion"></param>
        /// <param name="dllPath"></param>
        /// <param name="activeCode"></param>
        private static void CreateActiveCodeToReg(string cadVersion, string dllPath, string activeCode)
        {
            string dllName = Path.GetFileNameWithoutExtension(dllPath);
            RegistryKey keyCurrentUserMachine = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64);
            using (RegistryKey key = keyCurrentUserMachine.OpenSubKey("Software",true))
            {
                RegistryKey autoCadActiveCodeKey = key.OpenSubKey("AutoCadActiveCode", true);
                if (autoCadActiveCodeKey == null)
                {
                    autoCadActiveCodeKey = key.CreateSubKey("AutoCadActiveCode",true);
                }
                var dllKey = autoCadActiveCodeKey.OpenSubKey(dllName, true);
                if (dllKey == null)
                {
                    dllKey = autoCadActiveCodeKey.CreateSubKey(dllName,true);
                }
                dllKey.SetValue("CADVERSION", cadVersion, RegistryValueKind.String);
                dllKey.SetValue("ACTIVECODE", activeCode, RegistryValueKind.String);
                dllKey.SetValue("DLLPATH",dllPath, RegistryValueKind.String);
            }
        }

        /// <summary>
        /// 检查是否有激活码
        /// </summary>
        /// <param name="cadVersion"></param>
        /// <param name="dllPath"></param>
        /// <param name="activeCode"></param>
        /// <returns></returns>
        public static bool CheckIsActive(string cadVersion, string dllPath,out string activeCode)
        {
            activeCode = null;
            string dllName = Path.GetFileNameWithoutExtension(dllPath);
            RegistryKey keyCurrentUserMachine = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64);
            using (RegistryKey key = keyCurrentUserMachine.OpenSubKey("Software", true))
            {
                RegistryKey autoCadActiveCodeKey = key.OpenSubKey("AutoCadActiveCode", true);
                if (autoCadActiveCodeKey == null)
                {
                    return false;
                }
                var dllKey = autoCadActiveCodeKey.OpenSubKey(dllName, true);
                if (dllKey == null)
                {
                    return false;
                }
                string _cadVersion = dllKey.GetValue("CADVERSION") as string;
                string _dllPath = dllKey.GetValue("DLLPATH") as string;
                if (_cadVersion == cadVersion && dllPath == _dllPath)
                {
                    activeCode = dllKey.GetValue("ACTIVECODE") as string;
                    return true;
                }
                return false;
            }
        }

        /// <summary>
        /// 将cad插件注册到注册表上面
        /// </summary>
        /// <param name="address"></param>
        /// <param name="dllFile"></param>
        /// <returns></returns>
        private static bool RegisteringCAD(string address, string dllFile)
        {
            try
            {
                RegistryKey keyUser = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64);
                RegistryKey user = keyUser.OpenSubKey(address, true);
                if (user != null)
                {
                    RegistryKey keyUserApp = user.OpenSubKey(Path.GetFileNameWithoutExtension(dllFile), true);
                    if (keyUserApp == null)
                    {
                        keyUserApp = user.CreateSubKey(Path.GetFileNameWithoutExtension(dllFile), true);
                        keyUserApp.SetValue("DESCRIPTION", Path.GetFileNameWithoutExtension(dllFile), RegistryValueKind.String);
                        keyUserApp.SetValue("LOADCTRLS", 2, RegistryValueKind.DWord);
                        keyUserApp.SetValue("LOADER", Path.GetFullPath(dllFile), RegistryValueKind.String);
                        keyUserApp.SetValue("MANAGED", 1, RegistryValueKind.DWord);
                    }
                    else
                    {
                        keyUserApp.SetValue("DESCRIPTION", Path.GetFileNameWithoutExtension(dllFile), RegistryValueKind.String);
                        keyUserApp.SetValue("LOADCTRLS", 2, RegistryValueKind.DWord);
                        keyUserApp.SetValue("LOADER", Path.GetFullPath(dllFile), RegistryValueKind.String);
                        keyUserApp.SetValue("MANAGED", 1, RegistryValueKind.DWord);
                    }

                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception e)
            {
                return false;
            }

        }




        /// <summary>
        /// 查找cad的注册表路径
        /// </summary>
        /// <param name="CadVersion"></param>
        /// <param name="cadRegAddress"></param>
        /// <returns></returns>
        private static string FindLocation(string CadVersion, out List<string> cadRegAddress)
        {
            cadRegAddress = new List<string>();
            RegistryKey keyLocalMachine = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
            using (RegistryKey key = keyLocalMachine.OpenSubKey("Software\\Autodesk\\HardCopy"))
            {
                if (key != null)
                {
                    string[] values = key.GetValueNames();
                    foreach (string value in values)
                    {
                        if (value.Contains(CadVersion))
                        {
                            RegistryKey subKey = keyLocalMachine.OpenSubKey("Software\\" + value);
                            var result = subKey.GetValue("AcadLocation");
                            if (result != null)
                            {
                                cadRegAddress.Add("Software\\" + value);
                                return result.ToString();
                            }
                        }
                    }
                }
                else
                {
                    Console.WriteLine("未找到 Autodesk 注册表项。");
                }
            }
            return "";
        }
    }
}
